import * as THREE from "../../three/build/three.module.js"
import {OrbitControls} from "./m__OrbitControls.js";
import { DecalGeometry } from "../../three/examples/jsm/geometries/DecalGeometry.js";
import { GLTFLoader } from "../../three/examples/jsm/loaders/GLTFLoader.js";

let scene, camera, renderer, 
scene2, scene3, fbo, fbo2,
raycaster, mousePos = new THREE.Vector2(), player,
decalMaterial, pointMaterial,
item,// item 主要物体模型
paintItems = [];// paintItems 可以被喷射的物体
const startPoint = new THREE.Object3D();
const points={active:[], inactive:[]}; // points数组 active存放飞行状态point, inactive存放待机状态point
let isLaunch = false;

let data={
    _bulletNum: 400,
    module:{},
    moduleName: ""
}
let moduleDatas=[
    {
        name:`鲨鱼`,
        path:`./shark3.gltf`,
        size:2,
        rotation:[-Math.PI,Math.PI/2,0],
    },{
        name:`鹦鹉`,
        path:`./Parrot2.gltf`,
        size:1.,
        rotation:[0,0,0],
    },{
        name:`马`,
        path:`./Horse.gltf`,
        size:1.,
        rotation:[0,0,0],
    }
]

init();
animate();

export2window();

function export2window(){
    window.THREE = THREE;
    window.scene = scene;
    window.camera = camera;
    window.renderer = renderer;
    window.points = points;
    window.data = data;
}



function init(){
    (function initThree(){
        let width = innerWidth; 
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(50, width/window.innerHeight, 0.01, 500);
        renderer = new THREE.WebGLRenderer();

        renderer.sortObjects = true;

        camera.position.z = 10;
        renderer.setSize(width, window.innerHeight);
        renderer.setClearColor(0x666666);
        document.body.appendChild(renderer.domElement);
        let control = new OrbitControls(camera, renderer.domElement);
        control.maxPolarAngle = Math.PI-0.1;
        control.minPolarAngle = 0.1;
    })();

    (function initOther(){
        var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
        fbo = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
        fbo2 = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
    })();

    (function initScene(){
        //==================================camera + startPoint=========================
        startPoint.position.set(1,-2,-1);
        player = new THREE.Group();
        player.position.copy(camera.position);
        player.add(startPoint);
        scene.add(player);
 
        //=====================================room==============================
        // let roomGeometry = new THREE.BoxBufferGeometry(10,10,10);
        let roomGeometry = new THREE.SphereBufferGeometry(10,30,30);
        for(let i = 0; i< roomGeometry.index.array.length; i+=3){
            let t0 = roomGeometry.index.array[i];
            roomGeometry.index.array[i] = roomGeometry.index.array[i+1];
            roomGeometry.index.array[i+1] = t0;
        }
        let room = new THREE.Mesh(
            roomGeometry,
            new THREE.MeshBasicMaterial({
                // color: 0xFF0000,
                color: 0x000000,
            })
        );
        scene.add(room);
        paintItems.push(room);


        //==============================item==================================

        const loader = new GLTFLoader();
        let moduleIndex = Math.floor(Math.random()*moduleDatas.length);
        data.moduleName = moduleDatas[moduleIndex].name;
        data.module = moduleDatas[moduleIndex];
        // let moduleIndex = 2;
        let moduleData = moduleDatas[moduleIndex];
        loader.load(moduleData.path,
            function(gltf){
                item = gltf.scene.children[0];
                scene.add( item );
                item.material = new THREE.MeshBasicMaterial({
                    color:0x000000
                })
                paintItems.push(item);

                item.rotation.set(...moduleData.rotation);
                item.scale.set(moduleData.size,moduleData.size,moduleData.size);
            }
        );

        //============================= light=====================================
        let light0 = new THREE.AmbientLight(0xffffff,.3);
        scene.add(light0);
        
        const lightD = 15; // 灯光离原点的距离
        const lightR = 25; // 灯光范围

        let light1 = new THREE.PointLight(0xffffff, 1, lightR);
        let light2 = new THREE.PointLight(0xffffff, 1, lightR);
        let light3 = new THREE.PointLight(0xffffff, 1, lightR);
        let light4 = new THREE.PointLight(0xffffff, 1, lightR);

        light1.position.set(0,lightD,0);
        light2.position.set(0,-0.5*lightD,0.866*lightD);
        light3.position.set(-0.75*lightD,-0.5*lightD,-0.433*lightD);
        light4.position.set(0.75*lightD,-0.5*lightD,-0.433*lightD);
        scene.add(light1,light2,light3,light4);

    })();

    (function initScene2(){
        scene2 = new THREE.Scene();
 
        //=====================================room==============================
        // let roomGeometry = new THREE.BoxBufferGeometry(10,10,10);
        let roomGeometry = new THREE.SphereBufferGeometry(10,30,30);
        for(let i = 0; i< roomGeometry.index.array.length; i+=3){
            let t0 = roomGeometry.index.array[i];
            roomGeometry.index.array[i] = roomGeometry.index.array[i+1];
            roomGeometry.index.array[i+1] = t0;
        }
        let room = new THREE.Mesh(
            roomGeometry,
            new THREE.MeshBasicMaterial({
                color: 0xaaccff,
            })
        );
        scene2.add(room);
        paintItems.push(room);


        //==============================item==================================

        const loader = new GLTFLoader();
        let moduleData = data.module;
        loader.load(moduleData.path,
            function(gltf){
                item = gltf.scene.children[0];
                scene2.add( item );
                // item.material = new THREE.MeshBasicMaterial({
                //     color:0x000000
                // })
                paintItems.push(item);

                item.rotation.set(...moduleData.rotation);
                item.scale.set(moduleData.size,moduleData.size,moduleData.size);
            }
        );

        //============================= light=====================================
        let light0 = new THREE.AmbientLight(0xffffff,.3);
        scene2.add(light0);
        
        const lightD = 15; // 灯光离原点的距离
        const lightR = 25; // 灯光范围

        let light1 = new THREE.PointLight(0xffffff, 1, lightR);
        let light2 = new THREE.PointLight(0xffffff, 1, lightR);
        let light3 = new THREE.PointLight(0xffffff, 1, lightR);
        let light4 = new THREE.PointLight(0xffffff, 1, lightR);

        light1.position.set(0,lightD,0);
        light2.position.set(0,-0.5*lightD,0.866*lightD);
        light3.position.set(-0.75*lightD,-0.5*lightD,-0.433*lightD);
        light4.position.set(0.75*lightD,-0.5*lightD,-0.433*lightD);
        scene2.add(light1,light2,light3,light4);

    })();

    (function initScene3(){
        scene3 = new THREE.Scene;
        let canvasPlane = new THREE.Mesh(

            new THREE.PlaneBufferGeometry(1,1),
            new THREE.ShaderMaterial({
                uniforms: {
                    fbo: {
                        value:fbo
                    },
                    fbo2: {
                        value:fbo2
                    },
                    process: {
                        value:0
                    }
                },
                vertexShader:`
                    varying vec2 vUv;
                    void main(){
                        vUv = vec2( uv.x, uv.y );
                        gl_Position = vec4(position*2.,1.);
                    }
                `,
                fragmentShader:`
                    uniform sampler2D fbo;
                    uniform sampler2D fbo2;
                    uniform float process;

                    varying vec2 vUv;
                    void main(){
                        vec4 pic1 = texture2D(fbo, vUv);
                        vec4 pic2 = texture2D(fbo2, vUv);

                        float a = process > vUv.x ? 1. : 0.;

                        gl_FragColor = mix(pic1, pic2, process);
                        // gl_FragColor = mix(pic1, pic2, a);
                    }
                `
            })
        )
        scene3.add(canvasPlane);
    })();

    (function initMaterial(){
        pointMaterial = new THREE.ShaderMaterial({
            uniforms: {
                color: { value: new THREE.Color( 0xffffff ) },
            },
            transparent:true,
            alphaTest:0.5,
            depthWrite: false,
            vertexShader:`
                attribute float size;
                attribute vec3 customColor;

                varying vec3 vColor;

                void main() {

                    float _size = 2.;
                    vColor = vec3(1,1,1);

                    // vColor = customColor;

                    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

                    gl_PointSize = _size * ( 300.0 / -mvPosition.z );

                    gl_Position = projectionMatrix * mvPosition;

                }
            `,
            fragmentShader:`
                uniform vec3 color;
                uniform sampler2D pointTexture;

                varying vec3 vColor;

                void main() {
                    vec2 uv = gl_PointCoord-.5;
                    float a = smoothstep(.4,.7,1.-length(uv)*1.5);

                    gl_FragColor = vec4(1.,1.,1.,a);
                    // gl_FragColor = vec4( color * vColor, 1.0 );
                    // gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );

                }
            `
        });

        const decalDiffuse =new THREE.TextureLoader().load( './decal-diffuse.png' );
        decalMaterial = new THREE.MeshPhongMaterial( {
            specular: 0x444444,
            map: decalDiffuse,
            normalScale: new THREE.Vector2( 1, 1 ),
            shininess: 30,
            transparent: true,
            depthTest: true,
            depthWrite: false,
            polygonOffset: true,
            polygonOffsetFactor: - 4,
            wireframe: false
        } );
        
    })();

    (function initRay(){
        raycaster = new THREE.Raycaster();
        let onClickPosition = new THREE.Vector2();

        renderer.domElement.addEventListener(`mousedown` , function(e){
            if(e.button != 0) return; // 如果不是左击, 直接跳出
            let rendererSize=renderer.getSize();
            
            mousePos.set(e.offsetX/rendererSize.x-.5, -(e.offsetY/rendererSize.y-.5));
            mousePos.x *= 2;
            mousePos.y *= 2;
            isLaunch = true;
        });

        renderer.domElement.addEventListener(`mousemove`,function(e){
            if(isLaunch){
                let rendererSize = renderer.getSize();
                mousePos.set(e.offsetX/rendererSize.x-.5, -(e.offsetY/rendererSize.y-.5));
                mousePos.x *= 2;
                mousePos.y *= 2;
            }
        });

        renderer.domElement.addEventListener(`mouseup` , function(e){
            isLaunch = false;
        });
    })();

    (function initUI(){
        (function initInfoBox(){
            const bulletNumEl = document.getElementById(`bulletNum`);
            Object.defineProperty(data,'bulletNum',{
                // bulletNum: 100,
                set: function(x){
                    if(x<0){
                        alert("弹药不足");
                        isLaunch = false;
                        data._bulletNum = 0;
                        bulletNumEl.innerText = data.bulletNum;
                    }else{
                        data._bulletNum = x;
                        bulletNumEl.innerText = data.bulletNum;
                    }
                },
                get(){
                    return data._bulletNum;
                }
            });
            data.bulletNum = data._bulletNum;
        })();

        (function initSelectBox(){
            let optionBox = document.getElementById(`optionBox`);
            for(let i=0; i<moduleDatas.length; i++){
                let name = moduleDatas[i].name;
                let button = document.createElement(`button`);
                button.innerText = name;
                button.onclick=function(){
                    if(data.moduleName==name){
                        showKey();
                    }else{
                        alert("回答错误, 惩罚扣除弹药200");
                        data.bulletNum -= 200;
                    }
                }
                optionBox.appendChild(button);
            }
        })();
        


    })();
}

function createPoint(intersection){
    // =============createMesh
    let positions = new Float32Array( 3 );
    positions[0]=0;
    positions[1]=0;
    positions[2]=0;
    let pointGeometry = new THREE.BufferGeometry();
    pointGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    let point = new THREE.Points(
        pointGeometry,
        pointMaterial
    );

    // =============set some attribute

    let traget = {};
    let offsetTraget = new THREE.Vector3();

    let goStartPoint = function(){
        startPoint.getWorldPosition(point.position);
    }

    let setTraget = function (intersection) {
        goStartPoint();
        traget.position = intersection.point;
        traget.object = intersection.object;

        let normal = intersection.face.normal.clone();
        normal.transformDirection( traget.object.matrixWorld );
        normal.multiplyScalar( 10 );
        normal.add( traget.position );


        let _tempObj = new THREE.Object3D();
        _tempObj.position.copy(traget.position);
        _tempObj.lookAt(normal);

        traget.orientation = new THREE.Euler();
        traget.orientation.copy(_tempObj.rotation);
        offsetTraget.copy(traget.position);
    }

    setTraget(intersection);

    return {
        mesh: point,
        traget: traget,
        offsetTraget: offsetTraget,
        setTraget: setTraget
    };
}

function pointsFly(){
    for(let i = 0; i < points.active.length; i++){
        let speed = 0.5;
        let point = points.active[i];
        let pos = point.mesh.position;
        let traget = point.offsetTraget;

        let direction = new THREE.Vector3();
        direction.copy(traget);
        direction.sub(pos);

        if(direction.length()<=speed){ 
            // 飞到终点,结束旅程,绘制标记
            mark(point.traget.object, point.traget.position, point.traget.orientation);
            // mark(point.offsetTraget, point.traget.position, point.traget.orientation);
            // pos.set(Math.random()*.5, Math.random()*.5 ,10);
            scene.remove(point.mesh);
            points.active.splice(i,1);
            points.inactive.push(point);
        }else{
            direction.normalize().multiplyScalar(speed);
            pos.add(direction);
        }
    }
}

function pointLaunch(intersection){
    if(isLaunch){
        let point;
        if(data.bulletNum-- <= 0) return;
        if(points.inactive.length ){
            point = points.inactive.shift();
        }else{
            point = createPoint(intersection);
        }
        point.setTraget(intersection);
        points.active.push(point);
        // point.mesh.position.set(Math.random()*.5,Math.random()*.5 ,10);
        scene.add(point.mesh);
    }
}

function mark(mesh,position,orientation){
    // console.log(mesh);
    let size = .7;
    let g = new DecalGeometry( mesh, position, orientation, new THREE.Vector3(size,size,size));
    let markMesh = new THREE.Mesh( g , decalMaterial );
    scene.add( markMesh );
}

function showKey(){
    let canvasPlane = scene3.children[0];
    canvasPlane.material.uniforms.process.value +=0.01;
    if(canvasPlane.material.uniforms.process.value <1){
        setTimeout(showKey,1000/60);
    }
    else{
        alert("回答正确");
    }
}

function render(){
    renderer.setRenderTarget(fbo);
    renderer.clear();
    renderer.render(scene, camera);

    renderer.setRenderTarget(fbo2);
    renderer.clear();
    renderer.render(scene2, camera);

    renderer.setRenderTarget( null );
    renderer.clear();
    renderer.render(scene3, camera);
}

function animate(){
    requestAnimationFrame(animate);
    pointsFly();
    player.position.copy(camera.position);
    player.rotation.copy(camera.rotation);
    if(isLaunch){
        let newMousePos = new THREE.Vector2();
        newMousePos.copy(mousePos).add( new THREE.Vector2( (Math.random()*.1-.05)/(window.innerWidth/window.innerHeight), Math.random()*.1-.05) );;
        
        raycaster.setFromCamera( newMousePos, camera );
        let intersection = raycaster.intersectObjects( paintItems );

        if(intersection.length){
            // console.log(intersection.length)
            pointLaunch(intersection[0])
        }
    }
    render();
}